package com.qf4.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/*
    通知对象
 */
@Component
@Aspect  //表示这个是一个切面，切面对应的通知对象为当前ServiceAdvice对象
public class ServiceAdvice {

    //配置切点
    @Pointcut("execution(* com.qf4.service..*.find*(..))")
    public void pt(){}
    @Pointcut("execution(* com.qf4.service..*.insert(..))")
    public void pt2(){}

    //配置通知类型

    /**
     * 不管执行什么通知类型的通知方法， aop都会将当前目标方法封装成一个连接点对象，传递到我们通知方法中
     *  可以利用这个连接点对象获取方法的签名信息：包、类、方法命、参数列表
     *  可以利用这个连接点对象获取方法具体参数值
     * @param jp
     */
//    @Before("pt()")
    public void before(JoinPoint jp){

        String signature = jp.getSignature().toLongString();
        System.out.println("方法的签名信息:" + signature);

        Object[] args = jp.getArgs();
        System.out.println("方法的参数：" + Arrays.toString(args));

        System.out.println("查询缓存....");
    }

//    @After("pt()")
    public void after(){
        System.out.println("after....");
    }

    /**
     * 目标方法的返回值只有在目标方法正常执行完后才能获取
     *  after通知有可能目标方法执行出现异常，是获取不到的
     *  只能在AfterReturning通知中才能获取
     * @param result
     */
//    @AfterReturning(value = "pt2()",returning = "result")
    public void afterReturning(Object result){
        System.out.println("afterReturning....");
        System.out.println("当前目标方法执行后的返回值是： " + result);
    }

    /**
     * 目标方法的异常只有在目标方法执行异常后才能获取
     * after通知有可能目标方法正常执行，是获取不到的
     * 只能在AfterThrowing通知中才能获取
     * @param t
     */
//    @AfterThrowing(value = "pt()",throwing = "t")
    public void afterThrowing(Throwable t){
        System.out.println("afterThrowing....");
    }

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("around....");

        Object proceed = null;
        try {

            //获取参数
            Object[] args = pjp.getArgs();
            String methodName = pjp.getSignature().getName();
            if (methodName.equals("findById")){
                //修改参数
                args[0] = 10;
            }

            System.out.println("before....");

            //执行目标方法
            proceed = pjp.proceed(args);

            System.out.println("afterReturning.... 结果是：" + proceed);
        } catch (Throwable e) {
            e.printStackTrace();

            System.out.println("afterThrowing....异常是：" + e.getMessage());

//            throw  e; //将异常抛出，交给调用方
        }finally {
            System.out.println("after....");
        }

        return proceed;
    }



}
